#include "in.h"

int MDBUpdate( struct MemTable *table , void *set_record , ... )
{
	va_list				valist ;
	struct MemField			set_field_array[ MDB_PARSE_SET_FIELD_ARRAY_MAXCOUNT ] ;
	size_t				set_field_array_count ;
	void				*where_record = NULL ;
	struct MemField			where_field_array[ MDB_PARSE_WHERE_FIELD_ARRAY_MAXCOUNT ] ;
	size_t				where_field_array_count ;
	
	struct MemIndex			*index = NULL ;
	
	struct MemIndexDataUnit		*index_dataunit = NULL ;
	char				*record_dataunit = NULL ;
	struct MemIndexDataUnit		*travel_index_dataunit = NULL ;
	char				*travel_record_data = NULL ;
	struct MemIndexDataUnit		*prev_index_dataunit = NULL ;
	char				*prev_record_data = NULL ;
	struct MemIndexDataUnit		*next_index_dataunit = NULL ;
	int				is_matched ;
	
	int				nret = 0 ;
	
	va_start( valist , set_record );
	
	nret = ConvertArgsToArray( valist , set_field_array , sizeof(set_field_array)/sizeof(set_field_array[0]) , & set_field_array_count ) ;
	if( nret )
	{
		TRACE_PRINTF( "ConvertArgsToArray set fields failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		TRACE_PRINTF( "ConvertArgsToArray set fields ok\n" );
	}
	
	where_record = va_arg( valist , void* ) ;
	
	nret = ConvertArgsToArray( valist , where_field_array , sizeof(where_field_array)/sizeof(where_field_array[0]) , & where_field_array_count ) ;
	if( nret )
	{
		TRACE_PRINTF( "ConvertArgsToArray where fields failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		TRACE_PRINTF( "ConvertArgsToArray where fields ok\n" );
	}
	
	va_end( valist );
	
	CreateCurrentTransaction( table->db );
	
	index = QueryExecuteSchedule( table , where_field_array , where_field_array_count ) ;
	if( index )
	{
		TRACE_PRINTF( "QueryExecuteSchedule return index->index_name[%s]\n" , index->index_name );
		
		if( index->is_unique && where_field_array_count == index->index_field_array_count )
		{
			TRACE_PRINTF( "index is unique\n" );
			
			index_dataunit = QueryIndexDataUnitTreeNode( where_record , index , index->index_field_array , index->index_field_array_count ) ;
			if( index_dataunit == NULL )
			{
				TRACE_PRINTF( "QueryIndexDataUnitTreeNode failed\n" );
				CancelCurrentTransaction( table->db );
				DestroyCurrentTransaction( table->db );
				return (tls_last_errno=MDB_INFO_SQL_NOT_FOUND);
			}
			else
			{
				TRACE_PRINTF( "QueryIndexDataUnitTreeNode return index_dataunit[%p]\n" , index_dataunit );
			}
			
			record_dataunit = index_dataunit->record_dataunit ;
			
			AppendUpdateUndoDataToCurrentTransaction( table , record_dataunit , set_record );
		}
		else
		{
			TRACE_PRINTF( "index is not unique or fields too few\n" );
			
			index_dataunit = QueryIndexDataUnitTreeNode( where_record , index , where_field_array , where_field_array_count ) ;
			if( index_dataunit == NULL )
			{
				TRACE_PRINTF( "QueryIndexDataUnitTreeNode failed\n" );
				CancelCurrentTransaction( table->db );
				DestroyCurrentTransaction( table->db );
				return (tls_last_errno=MDB_INFO_SQL_NOT_FOUND);
			}
			else
			{
				TRACE_PRINTF( "QueryIndexDataUnitTreeNode ok , index_dataunit[%p]\n" , index_dataunit );
			}
			
			record_dataunit = index_dataunit->record_dataunit ;
			
			travel_index_dataunit = index_dataunit ;
			while( travel_index_dataunit )
			{
				TRACE_PRINTF( "travel upping index_dataunit[%p]\n" , travel_index_dataunit );
				prev_index_dataunit = GetPrevIndexDataUnit( travel_index_dataunit ) ;
				if( prev_index_dataunit == NULL )
					break;
				
				prev_record_data = MDB_RECORD_DATAUNIT_TO_DATA(prev_index_dataunit->record_dataunit) ;
				is_matched = TestRecordMatched( prev_record_data , where_field_array , where_field_array_count , where_record ) ;
				if( is_matched )
					break;
				
				travel_index_dataunit = prev_index_dataunit ;
				TRACE_PRINTF( "travel upped index_dataunit[%p]\n" , travel_index_dataunit );
			}
			
			while( travel_index_dataunit )
			{
				TRACE_PRINTF( "travel downning index_dataunit[%p]\n" , travel_index_dataunit );
				next_index_dataunit = GetNextIndexDataUnit( travel_index_dataunit ) ;
				
				if( travel_index_dataunit > index_dataunit )
				{
					travel_record_data = MDB_RECORD_DATAUNIT_TO_DATA(travel_index_dataunit->record_dataunit) ;
					is_matched = TestRecordMatched( travel_record_data , where_field_array , where_field_array_count , where_record ) ;
					if( is_matched )
						break;
				}
				
				record_dataunit = travel_index_dataunit->record_dataunit ;
				
				AppendUpdateUndoDataToCurrentTransaction( table , record_dataunit , set_record );
				
				travel_index_dataunit = next_index_dataunit ;
				TRACE_PRINTF( "travel downed index_dataunit[%p]\n" , travel_index_dataunit );
			}
		}
	}
	else
	{
		TRACE_PRINTF( "QueryExecuteSchedule return no index\n" );
		
		record_dataunit = QueryFirstRecordWithoutIndex( table , where_record , where_field_array , where_field_array_count ) ;
		if( record_dataunit == NULL )
		{
			TRACE_PRINTF( "QueryFirstRecordWithoutIndex return NULL , throw SQL_NOT_FOUND\n" );
			CancelCurrentTransaction( table->db );
			DestroyCurrentTransaction( table->db );
			return (tls_last_errno=MDB_INFO_SQL_NOT_FOUND);
		}
		else
		{
			TRACE_PRINTF( "QueryFirstRecordWithoutIndex return record[%p]\n" , record_dataunit );
		}
		
		for( ; ; )
		{
			AppendUpdateUndoDataToCurrentTransaction( table , record_dataunit , set_record );
			
			record_dataunit = QueryNextRecordWithoutIndex( table , record_dataunit , where_record , where_field_array , where_field_array_count ) ;
			if( record_dataunit == NULL )
				break;
		}
	}
	
	nret = ExecuteCurrentTransaction( table->db ) ;
	if( nret )
	{
		CancelCurrentTransaction( table->db );
	}
	
	DestroyCurrentTransaction( table->db );
	
	return 0;
}

